//build 20240425
//The watchdog component is used to monitor whether an application is freezing. A timeout period is set, and if the watchdog is not fed within this time, the device will be automatically restarted.
//Note that you may need to initialize GPIO before using the watchdog timer.
import { watchdogClass } from './libvbar-b-dxwatchdog.so'
import dxMap from './dxMap.js'
import logger from './dxLogger.js'
import dxCommon from './dxCommon.js'

const map = dxMap.get("___watchdog")
const watchdogObj = new watchdogClass();

const watchdog = {}
watchdog.last = new Date().getTime()
/**
 * Turn on the watchdog device
 * @param {number} type Required
 * @param {string} id Handle ID, optional (a unique ID is required if initializing multiple instances).
 */
watchdog.open = function (type, id) {
	let pointer = watchdogObj.open(type)
	if (pointer === undefined || pointer === null) {
		throw new Error("watchdog.open: open failed")
	}
	dxCommon.handleId("watchdog", id, pointer)
}
/**
 * Control the switch of the specified channel
 * @param {number} chan Channel ID (required)
 * @param {string} id Handle ID, optional (must be consistent with the ID in init).
 * @returns true/false
 */
watchdog.enable = function (chan, id) {
	let pointer = dxCommon.handleId("watchdog", id)
	return watchdogObj.enable(pointer, chan)
}
/**
 * Start the watchdog master timer
 * @param {*} timeout Required
 * @param {string} id Handle ID, optional (must be consistent with the ID in init).
 * @returns true/false
 */
watchdog.start = function (timeout, id) {
	let pointer = dxCommon.handleId("watchdog", id)
	return watchdogObj.start(pointer, timeout)
}
/**
 * To determine if it's a power-on reset, check if the watchdog timer has been activated.
 * @param {string} id Handle ID, optional (must be consistent with the ID in init).
 * @returns true/false
 */
watchdog.isPoweron = function (id) {
	let pointer = dxCommon.handleId("watchdog", id)
	return watchdogObj.isPoweron(pointer)
}
/**
 * Restart a watchdog channel
 * @param {*} chan Channel ID (required)
 * @param {string} id Handle ID, optional (must be consistent with the ID in init).
 * @returns true/false
 */
watchdog.restart = function (chan, id) {
	let pointer = dxCommon.handleId("watchdog", id)
	return watchdogObj.restart(pointer, chan)
}
/**
 * Turn off the watchdog master timer.
 * @param {string} id Handle ID, optional (must be consistent with the ID in init).
 * @returns true/false
 */
watchdog.stop = function (id) {
	let pointer = dxCommon.handleId("watchdog", id)
	return watchdogObj.stop(pointer)
}
/**
 * Turn off watchdog device
 * @param {string} id Handle ID, optional (must be consistent with the ID in init).
 * @returns true/false
 */
watchdog.close = function (id) {
	let pointer = dxCommon.handleId("watchdog", id)
	return watchdogObj.close(pointer)
}
/**
 * The program continuously checks the watchdog timer status of each thread; if any thread fails to feed the watchdog timer, the restart function is not initiated.
 * @param {number} chan Channel ID (required)
 * @param {string} id Handle ID, optional (must be consistent with the ID in init).
 */
watchdog.loop = function (chan, id) {
	const now = new Date().getTime()
	const minus = now - watchdog.last
	if (minus > 3000 || minus < 0) {//A check every 3 seconds or a value less than 0 indicates an operation to change the time forward.
		watchdog.last = now
		let keys = map.keys()
		let check = true
		for (let i = 0; i < keys.length; i++) {
			let key = keys[i]
			let value = map.get(key)
			const temp = now - value.now
			if (temp > value.timeout * 1000 && temp < 1700000000) {
				logger.error(`The worker ${key} did not feed the dog in time.`, temp)
				check = false
				break
			}
		}
		if (check) {
			this.restart(chan, id)
		}
	}
}
/**
 * Feed watchdog of different threads
 * @param {string} flag The thread identifier, which is required and cannot be empty.
 * @param {number} timeout How long can a thread go without feeding the watchdog (in seconds)? The default is 10 seconds.
 */
watchdog.feed = function (flag, timeout = 10) {
	if (!flag || flag.length <= 0) {
		return
	}
	map.put(flag, { now: new Date().getTime(), timeout: timeout })
}

export default watchdog;
